package com.anruisi.hxmes.gateway.authorization;

import com.anruisi.hxmes.gateway.entity.MenuRoles;
import com.anruisi.hxmes.gateway.service.MenuRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

/**
 * 鉴权管理器，用于判断是否有资源的访问权限
 * @author cmy
 * @date 2021/5/21 15:24
 */
@Slf4j
@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Autowired
    private MenuRoleService menuRoleService;

    AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {

        List<MenuRoles> menus = menuRoleService.getAllMenusWithRole();
        String urlPath = authorizationContext.getExchange().getRequest().getURI().getPath();

        List<String> authorities = new ArrayList<>();
        for (MenuRoles bean : menus) {
            if (antPathMatcher.match(bean.getUrl(), urlPath)) {
                authorities.addAll(bean.getRoleName());
            }
        }

        Mono<AuthorizationDecision> authorizationDecisionMono = mono
                .filter(Authentication::isAuthenticated)
                .flatMapIterable(Authentication::getAuthorities)
                .map(GrantedAuthority::getAuthority)
                .any(roleName -> {
                    //roleName是当前用户的角色列表，可能呢会有多个，authorities数据库中匹配这个url的角色列表
                    log.info("访问路径：{}", urlPath);
                    log.info("用户角色roleName：{}", roleName);
                    log.info("资源需要权限authorities：{}", authorities);
                    return authorities.contains(roleName);
                })
                .map(AuthorizationDecision::new)
                .defaultIfEmpty(new AuthorizationDecision(false));
        return authorizationDecisionMono;

    }

}
